package com.block.api.interceptor;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.block.api.reqbean.ReqBeanUtil;
import com.block.common.bean.CommonParam;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.enums.AppEncryptStatusEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.security.util.ApiUtil;
import com.block.common.service.IAppEncryptService;
import com.block.common.service.IApplicationInfoService;
import com.block.common.service.IChannelCommonService;
import com.block.common.service.LogFactory;
import com.block.common.util.HttpReturnUtil;
import com.block.common.util.MapUtil;
import com.block.db.entity.AppEncrypt;
import com.block.db.entity.ApplicationInfo;
import com.block.db.entity.ChannelBaseInfo;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;


/**
 * 请求数据初始化处理的拦截器
 *
 * @author JackieQ
 * @since 2019/3/1
 */
//@Component
public class InitInterceptor implements HandlerInterceptor {

	private static final Logger log = LogFactory.getAppReq();
	private static final Logger logTime = LogFactory.getTimeLog();

	@Autowired
	private IAppEncryptService iAppEncryptService;
	@Autowired
	NotifyExceptionService notifyExceptionService;
	@Autowired
	IChannelCommonService channelCommonService;
	@Autowired
	IApplicationInfoService applicationInfoService;

	/**
	 * 请求前置拦截
	 *
	 * @param request  请求体
	 * @param response 响应体
	 * @param handler
	 * @return boolean
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		StringBuilder sb=new StringBuilder();
		Date startdate = new Date();
		InputStream in=null;
		String uri = request.getRequestURI();
		String ip= ServletUtil.getClientIP(request);
		AppEncrypt appEncrypt=null;
		try {
			String appId = request.getParameter("appId");
			JSONObject jsonObject = null;
			if (StrUtil.isEmpty(appId)) {
				log.info("从流中读取数据....");
				sb=   sb.append( IoUtil.read(request.getInputStream()));
				log.info("从流中读取数据....完成");
				//从请求参数中取出数据
				if(StrUtil.isEmpty(sb.toString()))
				{
					HttpReturnUtil.returnJson(response,appEncrypt, AppRspCodeConstant.REQ_MSG_NULL,"REQUEST MESSAGE NULL",startdate,uri);
					return false;
				}
				jsonObject=JSONObject.parseObject(sb.toString());
			}else{
				Map<String,String[]> params= request.getParameterMap();
				Map<String,String> map= MapUtil.mapArrayToMapStr(params);
				log.info("从parameterMap读取数据:{}",map);
				if(cn.hutool.core.map.MapUtil.isEmpty(map)){
					HttpReturnUtil.returnJson(response,appEncrypt, AppRspCodeConstant.REQ_MSG_NULL,"REQUEST MESSAGE NULL",startdate,uri);
					return false;
				}
				jsonObject=JSONObject.parseObject(JSON.toJSONString(map));
			}

			//请求数据为空
			if(ObjectUtil.isEmpty(jsonObject)){
				HttpReturnUtil.returnJson(response,appEncrypt, AppRspCodeConstant.REQ_MSG_NULL,"REQUEST MESSAGE NULL",startdate,uri);
				return false;
			}
			appId = jsonObject.getString("appId");
			log.info("【uri】"+uri);
			appEncrypt = iAppEncryptService.getByAppId(appId);
			if(appEncrypt==null){
				HttpReturnUtil.returnJson(response,null,AppRspCodeConstant.APPID_INFO_ERROR,"APPID INFO ERROR",startdate,uri);
				return false;
			}

			// 判断当前appEncrypt 是否可用
			if (!StrUtil.equals(String.valueOf(appEncrypt.getStatus()), AppEncryptStatusEnum.AVAILABLE.getValue())){
				HttpReturnUtil.returnJson(response,null,AppRspCodeConstant.APPID_INFO_ERROR,"APPID INFO ERROR",startdate,uri);
				return false;
			}

			// 请求来自app
			CommonParam commonParam = new CommonParam();
			commonParam.setReqIp(ip);
			String randomUuid = request.getHeader("randomUuid");
			commonParam.setRandomUuid(randomUuid);

			String channelCode = request.getHeader("channelCode");
			commonParam.setChannelCode(channelCode);

			Enumeration<String> headerNames = request.getHeaderNames();
			try {
				JSONObject headObject = new JSONObject();
				while (headerNames.hasMoreElements()){
					String key = headerNames.nextElement();
					String header = request.getHeader(key);
					headObject.put(key, header);
				}
				commonParam.setHeadObject(headObject);
			}catch (Exception exception){
				exception.printStackTrace();
			}

			ChannelBaseInfo channelBaseInfo = null;
			try {
				// 查询渠道信息
				channelBaseInfo = channelCommonService.getBaseInfoByCode(channelCode);
				if ( ObjectUtil.isEmpty(channelBaseInfo) ||
						ObjectUtil.equal(channelBaseInfo.getStatus(), Integer.valueOf(0)) ||
						ObjectUtil.equal(channelBaseInfo.getDelFlag(), Integer.valueOf(1))){
//					notifyExceptionService.notifyNoticeInfo(
//							"REQUEST",
//							"渠道(不可用)请求拦截",
//							StrUtil.format("{}|{}|{}|{}", channelCode, ObjectUtil.isNotEmpty(channelBaseInfo)?channelBaseInfo.getChannelName():"无信息", ip, uri),
//							null );

					// 渠道信息不可用，直接禁止请求系统信息
					HttpReturnUtil.returnJson(response,null,AppRspCodeConstant.REQ_CHANNEL_CODE_ERROR,"渠道不可用",startdate,uri);
					return false;
				}

				commonParam.setChannelName(channelBaseInfo.getChannelName());
			}catch (Exception exception){
				exception.printStackTrace();
				notifyExceptionService.notifyNoticeInfo("REQUEST", "请求信息处理异常：", "channelCode:"+channelCode, exception);
				// 渠道信息不可用，直接禁止请求系统信息
				HttpReturnUtil.returnJson(response,null,AppRspCodeConstant.REQ_CHANNEL_CODE_ERROR,"请求渠道异常",startdate,uri);
				return false;
			}

			log.info("req header:{}",JSONObject.toJSONString(commonParam));
			log.info("req body:{}",JSONObject.toJSONString(jsonObject));

			JSONObject tranData=  ApiUtil.dealReqData(appEncrypt,jsonObject, uri);
			for(Map.Entry entry: tranData.entrySet()){
				if("".equals(entry.getValue())){
					entry.setValue(null);
				}
			}

			ApplicationInfo applicationInfo = applicationInfoService.getAppInfoByAppCode(channelBaseInfo.getAppCode());

			commonParam.setApplicationInfo(applicationInfo);
			commonParam.setChannelBaseInfo(channelBaseInfo);

			request.setAttribute("oriData",jsonObject);
			request.setAttribute("tranData", tranData);
			request.setAttribute("appEncrypt", appEncrypt);
			request.setAttribute("startDate", startdate);
			request.setAttribute("channelBaseInfo", channelBaseInfo);
			request.setAttribute("applicationInfo", applicationInfo);
			request.setAttribute("uri", uri);
			request.setAttribute("ip",ip);
			request.setAttribute("commonParam",commonParam);
			request.setAttribute("token", tranData.getString("token"));
			request.setAttribute("tranDataBean", tranData.toJavaObject(ReqBeanUtil.getBeanClass(uri)));
			return  true;
		} catch (JSONException e){
			e.printStackTrace();
			log.error("拦截器处理异常json...",e);
			HttpReturnUtil.returnJson(response,appEncrypt,AppRspCodeConstant.PARAM_ERROR,"PARAM ERROR INIT EXEC",startdate,uri);
			return  false;
		}catch (Exception e) {
			e.printStackTrace();
			log.error("拦截器处理异常...",e);
			HttpReturnUtil.returnJson(response,appEncrypt,AppRspCodeConstant.SYS_EXCEPTION,"SYSTEM ERROR INIT EXEC",startdate,uri);
			notifyExceptionService.notifyException("",uri,ip,"initinterceptor不打印请求数据",e);
			return false;
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
		try {
			Date startDate = (Date) request.getAttribute("startDate");
			String uri = (String) request.getAttribute("uri");

			Date endDate = new Date();
			long execTime = endDate.getTime() - startDate.getTime();

			if (execTime > 300){
				JSONObject tranData = (JSONObject) request.getAttribute("tranData");
				logTime.info("【uri】{}【execTime】{}【tranData】{}", uri, execTime, tranData);
			}
		}catch (Exception exception){
			exception.printStackTrace();
			logTime.error("请求结束返回", exception);
		}
	}
}
